//
//	File: OyDirect3D9_main.cpp
//
#include "OyDirect3D9.h"
#include "DX9Shader\DX9ShaderDatabase.h"
#include "OyDirect3D9_MaterialSystem.h"
#include "MaterialSystem\MaterialRenderer.h"
#include "Font\OyFontManager.h"
#include "Camera\D3D9Camera.h"

/**
 * If in windowed mode this function lets you switch between
 * all available child windows given as parameter array to
 * the original Init() function call.
 */
HRESULT OyDirect3D9::UseWindow(UINT nHwnd) 
{
	LPDIRECT3DSURFACE9 pBack = NULL;

	if(!m_d3dpp.Windowed)
		return OY_OK;
	else if(nHwnd >= m_nNumhWnd)
		return OY_FAIL;

	// Set right viewport
	RECT rcWnd;
	GetClientRect(m_hWnd[nHwnd], &rcWnd);
	m_dwWidth   = rcWnd.right - rcWnd.left;
	m_dwHeight  = rcWnd.bottom - rcWnd.top;

	// try to get the right back buffer
	if( FAILED(	m_pChain[nHwnd]->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pBack) ) ) 
	{
		OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, L"error: GetBackBuffer() failed in UseWindow()");
		return OY_FAIL;
	}
   
	m_pDevice->SetRenderTarget(0, pBack);
	m_pDevice->SetDepthStencilSurface(m_pChainDepthSurface[nHwnd]);
	pBack->Release();
	m_nActivehWnd = nHwnd;

	return OY_OK;
}

/**
 * Clear the scene and prepare device for retrieving geometry.
 * -> IN: bool - clear color buffer?
 *        bool - clear depth buffer?
 *        bool - clear stencil buffer?
 */
HRESULT OyDirect3D9::BeginRendering(bool bClearPixel, 
									bool bClearDepth, 
									bool bClearStencil) 
{
	DWORD clearFlag = 0;

	if( bClearPixel || bClearDepth || bClearStencil )
	{
		if(bClearPixel)
			clearFlag |= D3DCLEAR_TARGET;
		if(bClearDepth)
			clearFlag |= D3DCLEAR_ZBUFFER;   
		if(bClearStencil && m_bStencil)
			clearFlag |= D3DCLEAR_STENCIL;

		if( FAILED(m_pDevice->Clear(0, NULL, clearFlag, m_ClearColor, 1.0f, 0)) ) 
		{
			OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, L"error: clear() failed in BeginRendering()");
			return OY_FAIL;
		}
	}
   
	if( FAILED(m_pDevice->BeginScene()) )
		return OY_FAIL;

	m_bIsSceneRunning = true;

	DX9GetShaderDatabase()->Tick();

	// If Engine have defered sync Resource
	GetSkinManager()->DeferedSyncResource();
	GetVertexCacheManager()->DeferedSyncResource();

	GetMaterialRenderer()->BeforeDrawRenderBatch();


	m_pDevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)&m_pCurrentCamera->m_mViewMatrix);
	m_pDevice->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&m_pCurrentCamera->m_mProjMatrix);



	return OY_OK;
}

/**
 * Just clear the scene. Only call this when Scene has already begun.
 * -> IN: bool - clear color buffer?
 *        bool - clear depth buffer?
 *        bool - clear stencil buffer?
 */
HRESULT OyDirect3D9::Clear(bool bClearPixel, bool bClearDepth, bool bClearStencil)
{
	DWORD clearFlag = 0;

	if(bClearPixel)   
		clearFlag |= D3DCLEAR_TARGET;
	if(bClearDepth)   
		clearFlag |= D3DCLEAR_ZBUFFER;
   
	if(bClearStencil && m_bStencil)
		clearFlag |= D3DCLEAR_STENCIL;

	if( m_bIsSceneRunning )
		m_pDevice->EndScene();

	if( FAILED(m_pDevice->Clear(0, NULL, clearFlag, m_ClearColor, 1.0f, 0)) )
	{
		OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, L"error: Clear() FAILED");
		return OY_FAIL;
	}

	if( m_bIsSceneRunning )
		m_pDevice->BeginScene();
   
	return OY_OK;
}

/**
 * End of render operations and flip scene to front buffer.
 */
void OyDirect3D9::EndRendering() 
{
	HRESULT hr;

	m_pDevice->EndScene();

	if(m_d3dpp.Windowed && (m_nNumhWnd > 0) )
		hr = m_pChain[m_nActivehWnd]->Present(NULL, NULL, NULL, NULL, 0);
	else
		hr = m_pDevice->Present(NULL, NULL, NULL, NULL);
	m_bIsSceneRunning = false;

	if( FAILED(hr) )
	{
		OyLog_Write_L2(OyXMLLog::Event, OyXMLLog::Engine, L"D3D9 Device Lost...");
		OnDeviceReset();
	}
}

/**
 * Change the color of the screen clearing operation.
 * -> IN: float - red
 *        float - green
 *        float - blue
 */
void OyDirect3D9::SetClearColor(float fRed, float fGreen, float fBlue)
{
	m_ClearColor = D3DCOLOR_COLORVALUE(fRed, fGreen, fBlue, 1.0f);
}

void OyDirect3D9::SetAmbientLight(float fRed, float fGreen, float fBlue)
{
	return;
}

HRESULT OyDirect3D9::CreateFontInManager(const char* FontName, 
	const char *FontFilePath, bool bBold, bool bItalic, DWORD dwSize)
{
	if( m_pFontManager->IsFontLoaded(FontName) )
		return OY_OK;

	if( !m_pFontManager->AddFont( FontName, FontFilePath, dwSize, bBold, bItalic ) )
		return OY_FAIL;

	m_pFontManager->SetActiveFont( FontName );

	return OY_OK;
}

void OyDirect3D9::SetActiveFont(const char* FontName)
{
	m_pFontManager->SetActiveFont( FontName );
}

void OyDirect3D9::PreCacheChar(const TCHAR* sText)
{
	m_pFontManager->PreCacheChar(sText);
}

HRESULT OyDirect3D9::DrawTextInPos(int xPos, int yPos, DWORD flag, float RealFontSize, UCHAR r, UCHAR g, UCHAR b,TCHAR* format, ...)
{
	va_list ArgPtr;
	va_start(ArgPtr, format);
	int Length = _vsctprintf(format, ArgPtr) + 1;
	if( Length > MAX_FONT_STRING )
	{
		OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, L"error: render text buffer overflow");
		return OY_BUFFERSIZE;
	}
	_vstprintf_s(m_FontString, Length, format, ArgPtr);
	va_end(ArgPtr);

	DWORD FontColor = D3DCOLOR_ARGB( 255, r, g, b );
	float screenPos_x = static_cast<float>(xPos);
	float screenPos_y = static_cast<float>(yPos);

	if( !m_pFontManager->DoDrawTextInPos(m_FontString, screenPos_x, screenPos_y, FontColor, flag, RealFontSize, false, false) )
		return OY_FAIL;

	return OY_OK;
}

void OyDirect3D9::BeginRenderText()
{
	OyMaterialSystem::MaterialList &Mat_List = GetOyMaterialSystem()->GetMaterialList();
	const OyMaterialSystem::D3D9MaterialInfo &FontMaterial_info = Mat_List[OyMaterialSystem::eMaterial_font];
	GetMaterialRenderer()->PushMaterial(FontMaterial_info.m_material, MM_Add);
	GetMaterialRenderer()->ComputeMaterialPass();
	GetMaterialRenderer()->OnePassPreRenderMaterial(0);
}

void OyDirect3D9::EndRenderText()
{
	if( FAILED( m_pFontManager->FlushAllFonts() ) )
		OyLog_Write_L1(OyXMLLog::Error, OyXMLLog::Engine, L"error: Flush all fonts FAILED");
	GetMaterialRenderer()->OnePassPostRenderMaterial(0);
	GetMaterialRenderer()->PopMaterial();
}

void OyDirect3D9::FlushRenderBatch()
{
	// Commit Dynamic Buffer
	GetVertexCacheManager()->ForcedCommitAll();

	GetMaterialRenderer()->QueueRenderBatch();
	GetMaterialRenderer()->DoDrawRenderBatch_Opaque();
	GetMaterialRenderer()->DoDrawRenderBatch_Transparent();
	GetMaterialRenderer()->AfterDrawRenderBatch();	

	// Clear Dynamic Buffer
	GetVertexCacheManager()->ForcedClearAll();
}